package com.colabo.j2ee.web.core.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Properties;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;

public class FileEncryptUtil {
	private static Key createKey() throws NoSuchAlgorithmException {// 创建一个密钥
		Security.insertProviderAt(new com.sun.crypto.provider.SunJCE(), 1);
		KeyGenerator generator = KeyGenerator.getInstance("DES");
		generator.init(new SecureRandom());
		Key key = generator.generateKey();
		return key;
	}

	/**
	 * 生成密钥文件
	 * 
	 * @param filePath密钥文件所在位置
	 */
	public static void createKeyFile(String filePath) {
		ObjectOutputStream oos = null;
		try {
			Key key = createKey();
			oos = new ObjectOutputStream(new FileOutputStream(filePath));
			if (oos != null) {
				oos.writeObject(key);
				oos.close();
			}
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (oos != null) {
					oos.close();
				}
			} catch (Exception ee) {
				ee.printStackTrace();
			}
		}
	}

	/**
	 * 随机生成加密key
	 */
	public static Key getKey(InputStream is) {
		ObjectInputStream ois = null;
		Key key = null;
		try {
			ois = new ObjectInputStream(is);
			if (ois != null) {
				key = (Key) ois.readObject();
				ois.close();
			}

		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		} finally {
			try {
				if (ois != null) {
					ois.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		return key;
	}

	/**
	 * 对数据进行加密
	 */
	private static byte[] doEncrypt(Key key, byte[] data) {
		try {
			Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
			cipher.init(Cipher.ENCRYPT_MODE, key);
			byte[] raw = cipher.doFinal(data);
			return raw;
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	/**
	 * 对文件进行加密
	 * 
	 * @param filePath
	 *            要加密文件路径
	 * @param keyFilePath
	 *            密钥文件
	 * @return
	 */
	public static String encryptToFile(String filePath, String keyFilePath) {
		FileInputStream in = null;
		FileOutputStream out = null;
		ByteArrayOutputStream bout = null;
		FileInputStream fis = null;
		try {
			File file = new File(filePath);
			in = new FileInputStream(file);
			bout = new ByteArrayOutputStream();
			byte[] tmpbuf = new byte[1024];
			int count = 0;
			while ((count = in.read(tmpbuf)) != -1) {
				bout.write(tmpbuf, 0, count);
				tmpbuf = new byte[1024];
			}
			in.close();
			byte[] orgData = bout.toByteArray();
			fis = new FileInputStream(keyFilePath);
			Key key = getKey(fis);
			byte[] raw = FileEncryptUtil.doEncrypt(key, orgData);
			file = new File("en_" + file.getName());
			out = new FileOutputStream(file);
			out.write(raw);
			out.close();
			fis.close();
			return file.getAbsolutePath();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (in != null) {
					in.close();
				}

				if (out != null) {
					out.close();
				}

				if (bout != null) {
					bout.close();
				}

				if (fis != null) {
					fis.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		return null;
	}

	/**
	 * 对文件进行加密
	 * 
	 * @param filePath
	 *            要加密文件路径
	 * @param keyFilePath
	 *            密钥文件
	 * @return
	 */
	public static void encryptToFile(String filePath, String keyFilePath , String enFileName) {
		FileInputStream in = null;
		FileOutputStream out = null;
		ByteArrayOutputStream bout = null;
		FileInputStream fis = null;
		try {
			File file = new File(filePath);
			in = new FileInputStream(file);
			bout = new ByteArrayOutputStream();
			byte[] tmpbuf = new byte[1024];
			int count = 0;
			while ((count = in.read(tmpbuf)) != -1) {
				bout.write(tmpbuf, 0, count);
				tmpbuf = new byte[1024];
			}
			in.close();
			byte[] orgData = bout.toByteArray();
			fis = new FileInputStream(keyFilePath);
			Key key = getKey(fis);
			byte[] raw = FileEncryptUtil.doEncrypt(key, orgData);
			file = new File(enFileName);
			out = new FileOutputStream(file);
			out.write(raw);
			out.close();
			fis.close();
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (in != null) {
					in.close();
				}

				if (out != null) {
					out.close();
				}

				if (bout != null) {
					bout.close();
				}

				if (fis != null) {
					fis.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

	}
	
	/**
	 * 解密properties文件
	 * 
	 * @param filePath
	 *            要解密的properties文件
	 * @param keyFilePath
	 *            密钥文件
	 * @return
	 */
	public static Properties decryptToProperties(InputStream fileStream, InputStream keyStream) {
		Properties prop = new Properties();
		FileInputStream fis = null;
		InputStream raw = null;
		try {
			//File file = new File(filePath);
			//fis = new FileInputStream(file);
			Key key = getKey(keyStream);
			raw = doDecrypt(key, fileStream);

			prop.load(raw);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (fis != null) {
					fis.close();
				}

				if (raw != null) {
					raw.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return prop;
	}
	
	/**
	 * 对数据进行解密
	 */
	private static InputStream doDecrypt(Key key, InputStream in) {

		ByteArrayOutputStream bout = null;
		try {
			Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
			cipher.init(Cipher.DECRYPT_MODE, key);
			bout = new ByteArrayOutputStream();
			byte[] tmpbuf = new byte[1024];
			int count = 0;
			while ((count = in.read(tmpbuf)) != -1) {
				bout.write(tmpbuf, 0, count);
				tmpbuf = new byte[1024];
			}
			in.close();
			byte[] orgData = bout.toByteArray();
			byte[] raw = cipher.doFinal(orgData);
			InputStream bin = new ByteArrayInputStream(raw);
			return bin;
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		} finally {
			try {
				if (in != null) {
					in.close();
				}
				if (bout != null) {
					bout.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 解密properties文件
	 * 
	 * @param filePath
	 *            要解密的properties文件
	 * @param keyFilePath
	 *            密钥文件
	 * @return
	 */
	public static Properties decryptToProperties(String filePath, String keyFilePath) {
		Properties prop = new Properties();
		FileInputStream fis = null;
		InputStream raw = null;
		try {
			File file = new File(filePath);
			fis = new FileInputStream(file);
			Key key = getKey(new FileInputStream(keyFilePath));
			raw = doDecrypt(key, fis);

			prop.load(raw);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (fis != null) {
					fis.close();
				}

				if (raw != null) {
					raw.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return prop;
	}

	/**
	 * 生成解密文件，文件名称加上rs_
	 * 
	 * @param filePath
	 *            加密文件路径
	 * @param keyFilePath
	 *            密钥文件路径
	 * @return 返回解密文件路径
	 */
	public static String decryptToFile(String filePath, String keyFilePath) {
		FileInputStream fis = null;
		FileOutputStream fos = null;
		InputStream raw = null;
		ByteArrayOutputStream bout = null;
		try {
			File file = new File(filePath);
			fis = new FileInputStream(file);
			Key key = getKey(new FileInputStream(keyFilePath));
			raw = doDecrypt(key, fis);
			bout = new ByteArrayOutputStream();
			byte[] tmpbuf = new byte[1024];
			int count = 0;
			while ((count = raw.read(tmpbuf)) != -1) {
				bout.write(tmpbuf, 0, count);
				tmpbuf = new byte[1024];
			}
			raw.close();
			byte[] orgData = bout.toByteArray();
			file = new File("rs_" + file.getName());
			fos = new FileOutputStream(file);
			fos.write(orgData);
			return file.getAbsolutePath();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (fis != null) {
					fis.close();
				}

				if (fos != null) {
					fos.close();
				}

				if (raw != null) {
					raw.close();
				}

				if (bout != null) {
					bout.close();
				}

			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return null;
	}
}